/**
 *  new运算符的原理
 *  步骤：
 *  1.一个新对象被创建
 *  2.该对象的__proto__属性指向该构造函数的原型，即Fn.prototype
 *  3.将执行上下文(this)绑定到新创建的对象中
 *  4.如果构造函数有返回值，那么这个返回值将取代第一步中创建的对象
 */
function myNew() {
  // 创建一个对象
  let obj = {}
  let constructor = Array.prototype.shift.call(arguments)
  // 该对象的__proto__属性指向该构造函数的原型
  obj.__proto__ = constructor.prototype
  // 将执行上下文(this)绑定到新创建的对象中
  let result = constructor.apply(obj, arguments)
  // 如果构造函数有返回值，那么这个返回值将取代第一步中新创建的对象。否则返回该对象
  if (result !== null && (typeof result === "object" || typeof result === "function")) { return result }
  return obj
}

function myNew2(fn) {
	const obj = Object.create(fn.prototype);
	result = fn.apply(obj, [...arguments].slice(1));
	return typeof result === "object" ? result : obj;
}

function Person(name, age) {
  this.name = name,
  this.age = age,
  this.say = function() {
    console.log("I am" + this.name)
  }
}

let obj = myNew(Person, "star", 20)
console.log(obj.name)
console.log(obj.age)
obj.say()